package cn.gemframe.service.impl;

import cn.gemframe.common.bean.response.RefreshTokenResp;
import cn.gemframe.constant.GemConstant;
import cn.gemframe.exception.status.GemErrorStatus;
import cn.gemframe.response.ResultData;
import cn.gemframe.service.GemSsoService;
import cn.gemframe.utils.GemStringUtlis;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class GemSsoServiceImpl implements GemSsoService {

	@Autowired
	private TokenStore tokenStore;
	@Autowired
	private ClientDetailsService clientDetailsService;
	@Autowired
	private AuthorizationServerTokenServices tokenServices;

	private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();

    /**
     * 删除token
     * @param request
     * @return
     */
	public String deleteToken(HttpServletRequest request) {
		String header = request.getHeader("Authorization");
		if (GemStringUtlis.isNoneBlank(header) && header.length() > 0) {
			String[] split = header.split("bearer");
			if(split == null || split.length < 2){
                return GemConstant.Result.FAILURE;
            }
			String tokenValue = split[1].trim();
			if (GemStringUtlis.isNoneBlank(tokenValue) && tokenValue.length() > 0) {
				OAuth2AccessToken readAccessToken = tokenStore.readAccessToken(tokenValue);
				if (readAccessToken != null) {
					tokenStore.removeAccessToken(readAccessToken);
					return GemConstant.Result.SUCCESS;
				}
			}
		}
		return GemConstant.Result.FAILURE;
	}

    /***
     * 刷新token
     * @param refresh_token
     * @return
     */
	public ResultData<RefreshTokenResp> refreshToken(String refresh_token) {

		try{
			if (refresh_token == null
					|| refresh_token.equalsIgnoreCase("null")
					|| refresh_token.length() == 0) {
				return ResultData.<RefreshTokenResp>getResultWithCode(GemErrorStatus.TOKEN_ISNULL);
			}
			Map<String, String> parameters = new HashMap<String, String>();
			parameters.put("grant_type", "refresh_token");
			parameters.put("refresh_token", refresh_token);
			ClientDetails client = clientDetailsService.loadClientByClientId(GemConstant.Auth.CLIENT_ID_NAME);
			TokenRequest tokenRequest = new TokenRequest(parameters, GemConstant.Auth.CLIENT_ID_NAME, client.getScope(),parameters.get("grant_type"));

			if (client != null) {
				oAuth2RequestValidator.validateScope(tokenRequest, client);
			}

			if (isAuthCodeRequest(parameters)) {
				if (!tokenRequest.getScope().isEmpty()) {
					tokenRequest.setScope(Collections.<String>emptySet());
				}
			}

			if (isRefreshTokenRequest(parameters)) {
				tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
			}

			OAuth2AccessToken token = tokenServices.refreshAccessToken(refresh_token,tokenRequest);
			if (token == null) {
                return ResultData.<RefreshTokenResp>getResultWithCode(GemErrorStatus.CREATE_TOKEN_ERROR);
			}

            RefreshTokenResp resp = RefreshTokenResp.builder()
                    .access_token(token.getValue())
                    .refresh_token(token.getRefreshToken().getValue())
                    .expires_in(token.getExpiresIn())
                    .build();

            return ResultData.<RefreshTokenResp>SUCCESS(resp);
		}catch (Exception e){
			log.error("---refresh_token:{}刷新异常",refresh_token);
            return ResultData.<RefreshTokenResp>getServerErrorResult(e.getMessage());
		}
	}

	private boolean isRefreshTokenRequest(Map<String, String> parameters) {
		return "refresh_token".equals(parameters.get("grant_type")) && parameters.get("refresh_token") != null;
	}

	private boolean isAuthCodeRequest(Map<String, String> parameters) {
		return "authorization_code".equals(parameters.get("grant_type")) && parameters.get("code") != null;
	}

	public void setOAuth2RequestValidator(OAuth2RequestValidator oAuth2RequestValidator) {
		this.oAuth2RequestValidator = oAuth2RequestValidator;
	}

}
